package com.monkey.utils;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by silentwu on 2015/6/30.
 */
public abstract class MonkeyUtils {
    public static final long MILLIS_PER_SECOND = 1000;
    public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
    public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
    public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR;
    /**
     * Default time format :  yyyy-MM-dd HH:mm:ss
     */
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    /**
     * Date include week
     */
    public static final String DATE_WEEK_FORMAT = "yyyy-MM-dd (E)";
    /**
     * Time format :  yyyy-MM-dd HH:mm
     */
    public static final String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm";
    public static final String TIME_FORMAT = "HH:mm";
    /**
     * Default date format
     */
    public static final String DATE_FORMAT = "yyyy-MM-dd";
    /**
     * Default month format
     */
    public static final String MONTH_FORMAT = "yyyy-MM";

    /**
     * DES算法密钥
     */
    private static final byte[] DES_KEY = {21, 1, -110, 82, -32, -85, -128, -65};

    private static String HanDigiStr[] = new String[]{"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};

    private static String HanDiviStr[] = new String[]{"", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "万", "拾", "佰", "仟"};

    /**
     * 判断对象是否Empty(null或元素为0)<br>
     * 实用于对如下对象做判断:String Collection及其子类 Map及其子类
     *
     * @param pObj 待检查对象
     * @return boolean 返回的布尔值
     */
    public static boolean isEmpty(Object pObj) {
        if (pObj == null)
            return true;
        if (pObj instanceof String) {
            if (((String) pObj).length() == 0) {
                return true;
            }
        } else if (pObj instanceof Collection) {
            if (((Collection) pObj).size() == 0) {
                return true;
            }
        } else if (pObj instanceof Map) {
            if (((Map) pObj).size() == 0) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断对象是否为NotEmpty(!null或元素>0)<br>
     * 实用于对如下对象做判断:String Collection及其子类 Map及其子类
     *
     * @param pObj 待检查对象
     * @return boolean 返回的布尔值
     */
    public static boolean isNotEmpty(Object pObj) {
        if (pObj == null)
            return false;
        if (pObj instanceof String) {
            if (((String) pObj).length() == 0) {
                return false;
            }
        } else if (pObj instanceof Collection) {
            if (((Collection) pObj).size() == 0) {
                return false;
            }
        } else if (pObj instanceof Map) {
            if (((Map) pObj).size() == 0) {
                return false;
            }
        }
        return true;
    }

    //============================货币大写转换==============================

    /**
     * 将货币转换为大写形式(类内部调用)
     */
    private static String positiveIntegerToHanStr(String numStr) {
        // 输入字符串必须正整数，只允许前导空格(必须右对齐)，不宜有前导零
        String RMBStr = "";
        boolean lastzero = false;
        boolean hasvalue = false; // 亿、万进位前有数值标记
        int len, n;
        len = numStr.length();
        if (len > 15)
            return "数值过大!";
        for (int i = len - 1; i >= 0; i--) {
            if (numStr.charAt(len - i - 1) == ' ')
                continue;
            n = numStr.charAt(len - i - 1) - '0';
            if (n < 0 || n > 9)
                return "输入含非数字字符!";

            if (n != 0) {
                if (lastzero)
                    RMBStr += HanDigiStr[0]; // 若干零后若跟非零值，只显示一个零
                // 除了亿万前的零不带到后面
                // if( !( n==1 && (i%4)==1 && (lastzero || i==len-1) ) )
                // 如十进位前有零也不发壹音用此行
                if (!(n == 1 && (i % 4) == 1 && i == len - 1)) // 十进位处于第一位不发壹音
                    RMBStr += HanDigiStr[n];
                RMBStr += HanDiviStr[i]; // 非零值后加进位，个位为空
                hasvalue = true; // 置万进位前有值标记

            } else {
                if ((i % 8) == 0 || ((i % 8) == 4 && hasvalue)) // 亿万之间必须有非零值方显示万
                    RMBStr += HanDiviStr[i]; // “亿”或“万”
            }
            if (i % 8 == 0)
                hasvalue = false; // 万进位前有值标记逢亿复位
            lastzero = (n == 0) && (i % 4 != 0);
        }

        if (RMBStr.length() == 0)
            return HanDigiStr[0]; // 输入空字符或"0"，返回"零"
        return RMBStr;
    }

    /**
     * 将货币转换为大写形式
     *
     * @param val 传入的数据
     * @return String 返回的人民币大写形式字符串
     */
    public static String numToRMBStr(double val) {
        String SignStr = "";
        String TailStr = "";
        long fraction, integer;
        int jiao, fen;

        if (val < 0) {
            val = -val;
            SignStr = "负";
        }
        if (val > 99999999999999.999 || val < -99999999999999.999)
            return "数值位数过大!";
        // 四舍五入到分
        long temp = Math.round(val * 100);
        integer = temp / 100;
        fraction = temp % 100;
        jiao = (int) fraction / 10;
        fen = (int) fraction % 10;
        if (jiao == 0 && fen == 0) {
            TailStr = "整";
        } else {
            TailStr = HanDigiStr[jiao];
            if (jiao != 0)
                TailStr += "角";
            // 零元后不写零几分
            if (integer == 0 && jiao == 0)
                TailStr = "";
            if (fen != 0)
                TailStr += HanDigiStr[fen] + "分";
        }
        // 下一行可用于非正规金融场合，0.03只显示“叁分”而不是“零元叁分”
        // if( !integer ) return SignStr+TailStr;
        return SignStr + positiveIntegerToHanStr(String.valueOf(integer)) + "元" + TailStr;
    }

    //============================日期=================================

    /**
     * 获取指定年份和月份对应的天数
     *
     * @param year  指定的年份
     * @param month 指定的月份
     * @return int 返回天数
     */
    public static int getDaysInMonth(int year, int month) {
        if ((month == 1) || (month == 3) || (month == 5) || (month == 7) || (month == 8) || (month == 10) || (month == 12)) {
            return 31;
        } else if ((month == 4) || (month == 6) || (month == 9) || (month == 11)) {
            return 30;
        } else {
            if (((year % 4) == 0) && ((year % 100) != 0) || ((year % 400) == 0)) {
                return 29;
            } else {
                return 28;
            }
        }
    }

    /**
     * 根据所给的起止时间来计算间隔的月数
     *
     * @param startDate 起始时间
     * @param endDate   结束时间
     * @return int 返回间隔月数
     */
    public static int periodAsMonths(java.sql.Date startDate, java.sql.Date endDate) {
        Calendar startCal = Calendar.getInstance();
        startCal.setTime(startDate);
        Calendar endCal = Calendar.getInstance();
        endCal.setTime(endDate);
        int startDateM = Calendar.MONTH;
        int startDateY = Calendar.YEAR;
        int enddatem = Calendar.MONTH;
        int enddatey = Calendar.YEAR;
        return (enddatey * 12 + enddatem) - (startDateY * 12 + startDateM);
    }

    /**
     * 根据所给的起止时间来计算间隔的天数
     *
     * @param startDate 起始时间
     * @param endDate   结束时间
     * @return int 返回间隔天数
     */
    public static int periodAsDays(Date startDate, Date endDate) {
        long startdate = startDate.getTime();
        long enddate = endDate.getTime();
        long interval = enddate - startdate;
        return (int) (interval / MILLIS_PER_DAY);
    }

    /**
     * 计算两个时间之间相差的小时数 ,
     * 精确到秒
     * 忽略 分钟,秒的差异, 如  2014-02-02 01:00:00 与 2014-02-02 02:59:25 之间的相差小时为 1
     *
     * @param time1 Date
     * @param time2 Another Date
     * @return Hours  or -1
     */
    public static long periodAsHours(Date time1, Date time2) {
        if (time1 == null || time2 == null) {
            return -1;
        }
        long periodAsMilliSeconds = time1.getTime() - time2.getTime();
        return Math.abs(periodAsMilliSeconds) / MILLIS_PER_HOUR;
    }

    public static long periodAsMinutes(Date time1, Date time2) {
        if (time1 == null || time2 == null) {
            return -1;
        }
        long periodAsMilliSeconds = time1.getTime() - time2.getTime();
        return Math.abs(periodAsMilliSeconds) / MILLIS_PER_MINUTE;
    }

    public static long periodAsSeconds(Date time1, Date time2) {
        if (time1 == null || time2 == null) {
            return -1;
        }
        long periodAsMilliSeconds = time1.getTime() - time2.getTime();
        return Math.abs(periodAsMilliSeconds) / MILLIS_PER_SECOND;
    }

    /**
     * 返回给定日期所在月的最后一天日期
     *
     * @param date Date
     * @return Last day
     */
    public static Date lastDateOfMonth(Date date) {
        if (date == null) {
            return null;
        }
        Calendar calendar = calendar();
        calendar.setTime(date);
        final int lastDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        calendar.set(Calendar.DAY_OF_MONTH, lastDay);
        return calendar.getTime();
    }

    public static Calendar calendar() {
        return Calendar.getInstance();
    }

    /**
     * 返回给定日期所在月的第一天日期
     *
     * @param date Date
     * @return First day
     */
    public static Date firstDateOfMonth(Date date) {
        if (date == null) {
            return null;
        }
        Calendar calendar = calendar();
        calendar.setTime(date);
        final int lastDay = calendar.getActualMinimum(Calendar.DAY_OF_MONTH);
        calendar.set(Calendar.DAY_OF_MONTH, lastDay);
        return calendar.getTime();
    }

    /**
     * 获取当前时间
     *
     * @return
     */
    public static Date now() {
        return new Date();
    }


    /**
     * 给指定的日期加 几天时间(正数) 或减几天(负数)
     *
     * @param date Date
     * @param days plus days
     * @return Plussed date
     */
    public static Date plusDays(Date date, int days) {
        if (date == null) {
            return null;
        }
        Calendar calendar = calendar();
        calendar.setTime(date);
        calendar.add(Calendar.DAY_OF_MONTH, days);
        return calendar.getTime();
    }

    /**
     * 给指定的日期添加 几个月(正数) 或减几个月(负数)
     *
     * @param date   Date
     * @param months plus months
     * @return Plussed date
     */
    public static Date plusMonths(Date date, int months) {
        if (date == null) {
            return null;
        }
        Calendar calendar = calendar();
        calendar.setTime(date);
        calendar.add(Calendar.MONTH, months);
        return calendar.getTime();
    }

    /**
     * 给指定日期添加小时数
     *
     * @param date
     * @param hours
     * @return Date
     */
    public static Date plusHours(Date date, int hours) {
        if (date == null) {
            return null;
        }
        Calendar calendar = calendar();
        calendar.setTime(date);
        calendar.add(Calendar.HOUR_OF_DAY, hours);
        return calendar.getTime();
    }

    /**
     * @param date
     * @param minutes
     * @return
     */
    public static Date plusMinutes(Date date, int minutes) {
        if (date == null) {
            return null;
        }
        Calendar calendar = calendar();
        calendar.setTime(date);
        calendar.add(Calendar.MINUTE, minutes);
        return calendar.getTime();
    }

    /**
     * 返回指定格式的字符型日期
     *
     * @param date
     * @param format
     * @return
     */
    public static String toDateText(Date date, String format) {
        SimpleDateFormat simpledateformat = new SimpleDateFormat(format);
        return simpledateformat.format(date);
    }

    /**
     * 将字符串型日期转换为日期型
     */
    public static Date getDate(String dateText, String pattern) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(pattern);
        try {
            return dateFormat.parse(dateText);
        } catch (ParseException e) {
            throw new IllegalStateException("Parse date from [" + dateText + "," + pattern + "] failed", e);
        }
    }

    /**
     * 根据日期获取星期
     */
    public static String toStrWeek(Date date) {
        final String dayNames[] = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) - 1;
        if (dayOfWeek < 0)
            dayOfWeek = 0;
        return dayNames[dayOfWeek];
    }

    /**
     * 传入日期，计算出是星期几
     *
     * @param date
     * @return week
     */
    public static int toNumWeek(Date date) {
        Calendar calendar = calendar();
        calendar.setTime(date);
        return calendar.get(Calendar.DAY_OF_WEEK);
    }


    /**
     * 判断是否为周末(周六或周日)
     *
     * @param date Date
     * @return True is weekend, otherwise false
     */
    public static boolean isWeekend(Date date) {
        if (date == null) {
            return false;
        }
        Calendar calendar = calendar();
        calendar.setTime(date);
        final int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
        return dayOfWeek == Calendar.SUNDAY || dayOfWeek == Calendar.SATURDAY;
    }

    //=========================随机数===========================

    /**
     * 获取start到end区间的随机数,不包含start+end
     *
     * @param start
     * @param end
     * @return
     */
    public static BigDecimal getRandom(int start, int end) {
        return new BigDecimal(start + Math.random() * end);
    }


    //=============================集合==============================

    /**
     * 去掉List重复的值 顺序会乱
     *
     * @param list
     */
    @SuppressWarnings("unchecked")
    public static void removeDuplicate(List list) {
        HashSet h = new HashSet(list);
        list.clear();
        list.addAll(h);
    }

    /**
     * 删除ArrayList中重复元素，保持顺序
     *
     * @param list
     */
    @SuppressWarnings("unchecked")
    public static void removeDuplicateWithOrder(List list) {
        Set set = new HashSet();
        List newList = new ArrayList();
        for (Object element : list) {
            if (set.add(element))
                newList.add(element);
        }
        list.clear();
        list.addAll(newList);
    }


    public static String uuid() {
        return UUID.randomUUID().toString().replaceAll("-", "").toUpperCase();
    }

    public static long numberUUID() {
        return UUID.randomUUID().getMostSignificantBits();
    }

    /**
     * 第一个首字母大写
     *
     * @param in
     * @return
     */
    public static String uppercaseFirstChar(String in) {
        if (in == null || in.length() == 0) {
            return in;
        }
        int length = in.length();
        StringBuilder sb = new StringBuilder(length);

        sb.append(Character.toUpperCase(in.charAt(0)));
        if (length > 1) {
            String remaining = in.substring(1);
            sb.append(remaining);
        }
        return sb.toString();
    }

    /**
     * 第一个首字母小写
     * @param in
     * @return
     */
    public static String lowercaseFirstChar(String in) {
        if (in == null || in.length() == 0) {
            return in;
        }
        int length = in.length();
        StringBuilder sb = new StringBuilder(length);

        sb.append(Character.toLowerCase(in.charAt(0)));
        if (length > 1) {
            String remaining = in.substring(1);
            sb.append(remaining);
        }
        return sb.toString();
    }


}
